/*
    <one line to give the library's name and an idea of what it does.>
    Copyright (C) 2013  Guillaume <email>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#ifndef MSSAMPLER_H
#define MSSAMPLER_H

#include<msScalarFunction.h>

namespace atomism
{
class msSampler : public msTreeMapper
{
      friend class msScalarFunction;

protected:	
       
      class msSamplingData{ public:

			    double Average,Integral,Max,Min;  

		            msSamplingData(){Max=-1e30;Min=1e30;Average=0;Integral=0;}
			    
			    msSamplingData operator*(double a){Average*=a;Integral*=a;Max*=a;Min*=a;return *this;}

			    std::string abstract(){ std::stringstream out;out<<" Min="<<Min<<" Max="<<Max<<" Average="<<Average<<" Integral="<<Integral; return out.str();}
			    };

      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  isSamplerRegisteredInPython;
      static msRegister* createInstance() { return new msSampler; }
      void registryInPython();
      //@} 

      msSampler() : msTreeMapper(){ constructVar("msSampler","Sampler","sampler");nScanned=0; }  
      
public:
  
     void update()  { msTreeMapper::update();
                      };
		     
     void initialize() { msTreeMapper::initialize();
			  };
			  
     static boost::shared_ptr<msSampler> New(){
             
               boost::shared_ptr<msSampler> T( new msSampler );
	       LOGGER_ENTER_FUNCTION_DBG("msSampler::New()",T->getFullId());
	       T->initialize(); T->update();
	       LOGGER_EXIT_FUNCTION();
	       return T;
	       }

      virtual boost::shared_ptr<msTreeMapper> clone() { 
            boost::shared_ptr<msSampler> clone = New(); 
	    clone->msTreeMapper::operator=(*this);					      
	    return clone;
            }  

      boost::shared_ptr<msTreeMapper> setCoordinates(boost::shared_ptr<msGeneralizedCoordinates> Coordinates);
       
      virtual bool getNextPoint(boost::shared_ptr<msGeneralizedCoordinates> coors){
				       
	      BOOST_THROW_EXCEPTION( msError("The function getNextPoint() is not implemented in this class, you need to use derived class"
				                                    ,"msSamplingData msSampler::getNextPoint(...)", getFullId()) );				   
	      }

      virtual boost::shared_ptr<msTreeMapper> getRndPoint(boost::shared_ptr<msGeneralizedCoordinates> coors){
		
              Coordinates->setRandom();	    
	      return mySharedPtr(); 
	      }

      virtual msSampler::msSamplingData sample( msScalarFunction& fct);
	
      msSampler::msSamplingData sample( msScalarFunction& fct , const msUnitsManager& units) {
	
	       setCoordinates( fct.getCoordinates() );
   	       if( Coordinates == boost::shared_ptr<msGeneralizedCoordinates>() )  
                   BOOST_THROW_EXCEPTION( msError("the scalar function providen do not have initialized coordinates"
				                 ,"msSamplingData msSampler::sample( msScalarFunction& fct , const msUnitsManager& units)",getFullId()) );

	       msSampler::msSamplingData s=sample(fct);

	       double fctConv  = units.convert(fct.getYUnit(),1);
	       double coorsConv = Coordinates->getVolumeDq(units) /  Coordinates->getVolumeDq() ;
               return  s*fctConv*coorsConv;
  	       };

      std::ostream& print(std::ostream&) const;

      virtual double scalarProduct(msScalarFunction& fct1 ,msScalarFunction& fct2);
      
      virtual void begin() { nScanned=0;}
      
      size_t noOfScanned(){return nScanned;}
      
protected:

      boost::shared_ptr<msGeneralizedCoordinates> Coordinates;	
      
      size_t 	AffStep;       //!< Step to display the integration point when Integrate() is called
      
      int 	nScanned;      //!< number of point already Scanned
 };
 std::ostream& operator<<(std::ostream& out,const msSampler& sampler);
}

#endif // MSSAMPLER_H
